/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.form.compat2.layouts; import java.awt.*; import java.beans.*; import java.util.Iterator; import org.netbeans.modules.form.util2.NbVersion; import org.netbeans.modules.form.util2.NbVersionNotCompatibleException; import org.openide.nodes.Node; import org.netbeans.modules.form.*; /** An abstract superclass of design-time supports for LayoutManagers. * * @author Ian Formanek */ public abstract class DesignLayout extends Object implements java.io.Externalizable, Cloneable { /** A JDK 1.1 serial version UID */ static final long serialVersionUID = -1684801460008455378L; /** Netbeans class version */ public static final NbVersion nbClassVersion = new NbVersion (1, 0); /** A constant for design-mode of layout. The design-mode might add * an additional advanced design-time behaviour of the layout. * E.g. a BorderLayout in design-mode marks the directions (North, South, ...) * and keeps the sizes same regardless of what components are added to the layout. */ public final static int DESIGN_MODE = 1; /** A constant for real-mode of layout. The layout in real-mode * behaves exactly the same way as during the run-time of the application. */ public final static int REAL_MODE = 2; /** Default icons for DesignLayout. */ static protected Image defaultIcon; static protected Image defaultIcon32; static { defaultIcon = Toolkit.getDefaultToolkit ().getImage ( DesignLayout.class.getResource ("/org/netbeans/modules/form/resources/formLayout.gif")); // NOI18N defaultIcon32 = Toolkit.getDefaultToolkit ().getImage ( DesignLayout.class.getResource ("/org/netbeans/modules/form/resources/formLayout32.gif")); // NOI18N } // ----------------------------------------------------------------------------- // private variables /** The container which is managed by this DesignLayout. * It is transient so as the setRADContainer is called after deserialization */ transient private RADVisualContainer container; /** array of listeners */ transient private PropertyChangeSupport support = new PropertyChangeSupport (this); /** The curent mode of this layout * @see #DESIGN_MODE * @see #REAL_MODE */ transient private int mode = DESIGN_MODE; // FINALIZE DEBUG METHOD public void finalize () throws Throwable { super.finalize (); if (System.getProperty ("netbeans.debug.form.finalize") != null) { System.out.println("finalized: "+this.getClass ().getName ()+", instance: "+this); // NOI18N } } // FINALIZE DEBUG METHOD /** Can be called to create a clone of the design layout. * The default implemetation creates new instance using the default constructor and * clones all changed properties. If other behavior is desired, this method can be overriden. * @return a new instance of this design layout with the same properties */ public Object clone () throws CloneNotSupportedException { try { DesignLayout newLayout = (DesignLayout)getClass ().newInstance (); java.util.List changedProps = getChangedProperties (); java.util.Map newChanged = new java.util.HashMap (changedProps.size () * 2); for (Iterator it = changedProps.iterator (); it.hasNext ();) { Node.Property prop = (Node.Property)it.next (); try { newChanged.put (prop.getName (), FormUtils.cloneObject (prop.getValue ())); } catch (Exception e) { // ignore property with problem if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N } } newLayout.initChangedProperties (newChanged); return newLayout; } catch (Exception e) { throw new CloneNotSupportedException (); } } /** Assigns this DesignLayout to the specified RADVisualContainer. * @param cont The RADVisualContainer that represents a container that will be * managed by this layout or null as a notification that this layout * is not a designLayout for its current container anymore */ public void setRADContainer (RADVisualContainer cont) { container = cont; if ((cont != null) && (cont.getFormManager () != null)) mode = cont.getFormManager ().getMode (); } /** @return The container managed by this DesignLayout */ public RADVisualContainer getRADContainer() { return container; } /** @return The FormManager2 that manages this form */ protected FormManager2 getFormManager() { return container.getFormManager (); } /** A utility method for subclasses that allows quick access to the * @return The AWT container component of the container managed * by this DesignLayout or null if not yet initialized */ final protected Container getContainer() { if (getRADContainer () != null) { return getRADContainer ().getContainer (); } else { return null; } } /** Method which allows the design layout to provide list of properties to be saved with the form. * @return list of Node.Property objects */ public java.util.List getChangedProperties () { return new java.util.ArrayList (0); } /** Method which is called after the layout is loaded with the form to initialize its properties. * @param cahngedProperties map of <String, Object> pairs, where the String is a name of property and the Object its value */ public void initChangedProperties (java.util.Map changedProperties) { } /** Sets the current mode of this layout. * Descendants must override this method to provide any additional * functionality needed when layout mode is switched. * @see #DESIGN_MODE * @see #REAL_MODE * @see #getMode */ public void setMode(int mode) { this.mode = mode; } /** Sets the current mode of this layout. * @see #DESIGN_MODE * @see #REAL_MODE * @see #getMode */ public int getMode() { return mode; } /** A design layout may provide a customizer for advanced layout * customization (e.g. for GridBagLayout). * Might return null, if the customizer is not available. * The default implementation returns null. * @return customizer for this design layout or null if it has no customizer */ public Class getCustomizerClass() { return null; } /** An icon of the design-layout. This icon will be used on the ComponentPalette * for this layout's item. * @param type the desired type of the icon (BeanInfo.ICON_???) * @return layout's icon. */ public Image getIcon(int type) { if ((type == BeanInfo.ICON_COLOR_16x16) || (type == BeanInfo.ICON_MONO_16x16)) return defaultIcon; else return defaultIcon32; } /** Returns a description of the constraints for the * specified position. The constraints description object will be used * for adding, getting textual description of the constraints and * the popup menu. * The default implementation just returns the default constraints * description. * @param position The position within the container for which the * constraints description should be returned. */ public abstract ConstraintsDescription getConstraintsDescription(Point position); /** A display name of the layout will be used for displaying the layout in * the components hierarchy during design-time. * @return layout's display name. */ public abstract String getDisplayName(); /** Returns the global layout's properties (i.e. the properties * that are not different for different components in the layout. * The default implementation returns empty array. * @return the global layout properties */ public Node.PropertySet[] getPropertySet () { return new Node.PropertySet[0]; } /** Returns the layout's properties for specified component. * The default implementation returns empty array. * @param component the RADVisualComponent of the component which properties we request * @return the layout-specific properties for specified component */ public Node.Property[] getComponentProperties(RADVisualComponent component) { return new Node.Property[0]; } /** Returns a class of the layout that this DesignLayout represents (e.g. * returns FlowLayout.class from DesignFlowLayout). * @return a class of the layout represented by this DesignLayout or null if the * design layout does not represent a "real" layout (e.g. support layouts for JTabbedPane, ...) */ public abstract Class getLayoutClass(); // ----------------------------------------------------------------------------- // Child components management /** Adds specified component to this layout. The constraints for the component * are acquired from the component by method getConstraints(). * The default implementation adds the visual representation of the specified component * to the position acquired from the component by calling getComponentIndex (). * @param component The component to add * @see RADVisualComponent#getConstraints * @see RADVisualComponent#setConstraints * @see RADVisualComponent#getComponentIndex * @see #removeComponent */ public void addComponent (RADVisualComponent component) { getContainer().add(getFormManager ().getVisualRepresentation (component), component.getComponentIndex ()); } /** Adds specified component to this layout with specified constraints. * The constraints for the component are saved in the component by calling setConstraints. * @param component The component component to add * @param desc The constraints to add the component with * @see RADVisualComponent#getConstraints * @see RADVisualComponent#setConstraints * @see #removeComponent */ public void addComponent (RADVisualComponent component, ConstraintsDescription desc) { component.setConstraints (getClass (), desc); addComponent (component); } /** Removes specified component from this layout. * The default implementation removes the visual representation of the specified component * from the container. * @param component The component to remove * @see #addComponent */ public void removeComponent (RADVisualComponent component) { getContainer().remove(getFormManager ().getVisualRepresentation (component)); } /** Called to update the layout. Should readd all the visual components to * reflect any global or ordering changes. * The default implementation simply removes all visual representations of all * children from the container, calls the single-argument version of addComponent () * on all the children again and validates and repaints the container. */ public void updateLayout () { getContainer ().removeAll (); RADVisualComponent[] children = getRADContainer ().getSubComponents (); for (int i=0; i < children.length; i++) { addComponent (children[i]); } getContainer ().validate (); getContainer ().repaint (); } // ----------------------------------------------------------------------------- // Drag'n'drop support /** A design layout that supports moving components should redefine * this method and return true. * @return true if the design layout supports moving, false otherwise * @see #moveTo */ public boolean canMove () { return false; } /** A design layout that supports moving components should redefine * this method to modify the constraints according to the supplied * delta positions (difference between the old and the new position). * @param desc the constraints to move from * @param deltaX the delat move in x axis * @param deltaY the delta move in y axis * @param hotSpot The hotspot on the component (the point where the user started * the drag on the component) * @return the new modified ConstraintsDescription * @see #canMove */ public ConstraintsDescription moveTo (ConstraintsDescription desc, int deltaX, int deltaY, Point hotSpot) { throw new IllegalStateException (); } /** A design layout that supports resizing components should redefine * this method and return true. * The resizing includes a initial drag-resize when adding a new component. * @return true if the design layout supports resizing, false otherwise * @see #resizeTo */ public boolean canResize () { return false; } /** A design layout that supports resizing components should redefine * this method to modify the constraints according to the supplied * new size. * @param desc the constraints to resize from * @param width the width to resize to * @param height the height to resize to * @return the new modified ConstraintsDescription * @see #canResize */ public ConstraintsDescription resizeTo (ConstraintsDescription desc, int width, int height) { throw new IllegalStateException (); } /** A design layout that supports *BOTH* resizing and moving components * should redefine this method to modify the constraints according to the supplied * new bounds. * @param desc the constraints to resize from * @param bounds the bounds to resize to * @see #canMove * @see #canResize */ public ConstraintsDescription resizeToBounds (ConstraintsDescription desc, Rectangle bounds) { return null; } /** Called to inform the Layout that it should provide a design-time visual * feedback for a "move" action of the specified component to the specified constraints. * @param component The RADVisualComponent that is being dragged * @param desc The "drag to" constraints or null for ending the marking operation */ public void markMoveTo (RADVisualComponent component, ConstraintsDescription desc) { } /** Called to inform the Layout that it should provide a design-time visual * feedback for a "resize" action to the specified constraints. * @param desc The "resize to" constraints or null to notify about cancelling the resize operation */ public void markResizeTo (ConstraintsDescription desc) { } /** Called to inform the Layout that it should provide a design-time visual * feedback for a "resize" action of the specified component to the specified constraints. * @param component The RADVisualComponent that is being resized * @param desc The "resize to" constraints */ // public void markResizeTo (RADVisualComponent component, ConstraintsDescription desc) { // } // ----------------------------------------------------------------------------- // Code generation /** Generates the code for initialization of this layout, e.g. panel1.setLayout (new BorderLayout ());. * @param cont The container that is managed by this layout * @return the init code for the layout or null if it should not be generated */ public abstract String generateInitCode(RADVisualContainer cont); /** Generates the code for adding specified component to this layout. * @param comp The component to be added to this layout * @param cont The container that is managed by this layout */ public abstract String generateComponentCode(RADVisualContainer cont, RADVisualComponent comp); /** Support function used for creating name of container with a dot (if necessarily). */ protected String createContainerGenName(RADVisualContainer container) { return container.getContainerGenName(); } // ----------------------------------------------------------------------------- // listeners /** Fire a property change event. For one property listed in * the array of properties that can be obtained by * <CODE>getProperties ()</CODE>. * @param component the component which layout property changed or null if layout's own property changed * @param name name of changed property * @param o old value * @param n new value */ public final void firePropertyChange (RADVisualComponent component, String name, Object o, Object n) { if (component == null) { if (container.getLayoutNodeReference () != null) { container.getLayoutNodeReference ().fireLayoutPropertiesChange (); } getFormManager().fireLayoutChanged (container, null, name, o, n); } else { getFormManager().fireLayoutChanged (container, component, name, o, n); component.notifyPropertiesChange (); } } // ----------------------------------------------------------------------------- // Serialization /** Writes the object to the stream. * @param oo output stream to write to * @exception IOException Includes any I/O exceptions that may occur */ public void writeExternal (java.io.ObjectOutput oo) throws java.io.IOException { // store version oo.writeObject (nbClassVersion); } /** Reads the object from stream. * @param oi input stream to read from * @exception IOException Includes any I/O exceptions that may occur * @exception ClassNotFoundException if the class of the read object is not found */ public void readExternal (java.io.ObjectInput oi) throws java.io.IOException, ClassNotFoundException { org.netbeans.modules.form.FormUtils.DEBUG(">> DesignLayout: readExternal: START"); // NOI18N // check the version NbVersion classVersion = (NbVersion) oi.readObject (); if (!nbClassVersion.isCompatible (classVersion)) throw new NbVersionNotCompatibleException (classVersion, nbClassVersion); org.netbeans.modules.form.FormUtils.DEBUG("<< DesignLayout: readExternal: END"); // NOI18N } // ------------------------------------------------------------------------ // ConstraintsDescription innerclass /** The ConstraintsDescription class encapsulates constraints data and * operations on a constraints that will be used for adding components * to the layout. * The instances of ConstraintsDescription should be DesingLayout instance-independent, * i.e. it should be possible to use one ConstraintsDescription instance in multiple * different DesignLayout instances (of appropriate type). */ public static class ConstraintsDescription implements java.io.Externalizable { /** A JDK 1.1 serial version UID */ static final long serialVersionUID = 2035633473805900956L; /** Netbeans class version */ public static final NbVersion nbClassVersion = new NbVersion (1, 0); /** Returns a textual descriptions of constraints represented by this * class. E.g. for BorderLayout, it is a text "Center" or "North". * @return textual descriptions of the constraints */ public String getConstraintsString() { return ""; // NOI18N } /** Returns the constraints represented by this class. E.g. for * BorderLayout, it is a String "Center" or "North". * The default implementation simply returns null. * @return the constraints represented by this class or null if the * constraints are empty / not appliable */ public Object getConstraintsObject() { return null; } /** * @return the Constraints class and constraints string */ public String toString() { return getClass() + ": " + getConstraintsString(); // NOI18N } /** Two ConstraintsDescriptions are equal if its constraints objects * (returned from getConstraintsObject) are equal or both null. * @return true if this ConstraintsDescriptions is equal to the one passed as a parameter */ public boolean equals (Object o) { if (!(o instanceof ConstraintsDescription)) return false; Object con = ((ConstraintsDescription)o).getConstraintsObject (); if (getConstraintsObject () == null) return (con == null) ? true : false; else return (con == null) ? false : con.equals (getConstraintsObject ()); } /** The hashCode of a ConstraintsDescription is the hashCode of its constraints objects * (returned from getConstraintsObject) or (if it is null) its class. * @return the hashCode of this ConstraintsDescription */ public int hashCode () { return (getConstraintsObject () != null) ? getConstraintsObject ().hashCode () : getClass().hashCode (); } // ----------------------------------------------------------------------------- // Serialization /** Writes the object to the stream. * @param oo output stream to write to * @exception IOException Includes any I/O exceptions that may occur */ public void writeExternal (java.io.ObjectOutput oo) throws java.io.IOException { // store version oo.writeObject (nbClassVersion); } /** Reads the object from stream. * @param oi input stream to read from * @exception IOException Includes any I/O exceptions that may occur * @exception ClassNotFoundException if the class of the read object is not found */ public void readExternal (java.io.ObjectInput oi) throws java.io.IOException, ClassNotFoundException { org.netbeans.modules.form.FormUtils.DEBUG(">> ConstraintsDescription: readExternal: START"); // NOI18N // check the version NbVersion classVersion = (NbVersion) oi.readObject (); if (!nbClassVersion.isCompatible (classVersion)) throw new NbVersionNotCompatibleException (classVersion, nbClassVersion); org.netbeans.modules.form.FormUtils.DEBUG("<< ConstraintsDescription: readExternal: END"); // NOI18N } // ----------------------------------------------------------------------------- // XML Persistence /** Called to load property value from specified XML subtree. If succesfully loaded, * the value should be available via the getValue method. * An IOException should be thrown when the value cannot be restored from the specified XML element * @param element the XML DOM element representing a subtree of XML from which the value should be loaded * @exception IOException thrown when the value cannot be restored from the specified XML element */ public void readFromXML (org.w3c.dom.Node element) throws java.io.IOException { } /** Called to store current property value into XML subtree. The property value should be set using the * setValue method prior to calling this method. * @param doc The XML document to store the XML in - should be used for creating nodes only * @return the XML DOM element representing a subtree of XML from which the value should be loaded or null * if the value does not need to save any additional data and can be created using the default constructor */ public org.w3c.dom.Node storeToXML(org.w3c.dom.Document doc) { return null; } } } /* * Log * 23 Gandalf 1.22 1/12/00 Ian Formanek NOI18N * 22 Gandalf 1.21 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 21 Gandalf 1.20 10/5/99 Ian Formanek Cloning of layout * supported * 20 Gandalf 1.19 9/24/99 Ian Formanek Smarter code generation * - fixes bug 4016 - The setLayout code should not be generated if the * layout is already set on the container to prevent loosing components * already on the panel. * 19 Gandalf 1.18 9/24/99 Ian Formanek generateInitCode method * clarified * 18 Gandalf 1.17 9/17/99 Ian Formanek Fixed bug 1825 - * Property sheets are not synchronized * 17 Gandalf 1.16 7/31/99 Ian Formanek Cleaned up comments * 16 Gandalf 1.15 7/13/99 Ian Formanek XML Persistence * 15 Gandalf 1.14 7/13/99 Ian Formanek Added changedProperties * to support XML Serialization * 14 Gandalf 1.13 6/27/99 Ian Formanek Removed indent parameter * from code generation methods * 13 Gandalf 1.12 6/22/99 Ian Formanek Modified customizers * 12 Gandalf 1.11 6/10/99 Ian Formanek Regeneration on layout * changes * 11 Gandalf 1.10 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 10 Gandalf 1.9 5/31/99 Ian Formanek Design/Test Mode * 9 Gandalf 1.8 5/15/99 Ian Formanek * 8 Gandalf 1.7 5/14/99 Ian Formanek * 7 Gandalf 1.6 5/14/99 Ian Formanek * 6 Gandalf 1.5 5/12/99 Ian Formanek * 5 Gandalf 1.4 5/11/99 Ian Formanek Build 318 version * 4 Gandalf 1.3 5/10/99 Ian Formanek * 3 Gandalf 1.2 5/4/99 Ian Formanek package change * (formeditor -> ..) * 2 Gandalf 1.1 3/29/99 Ian Formanek Uses FormUtils.DEBUG to * print messages * 1 Gandalf 1.0 3/28/99 Ian Formanek * $ */